﻿using Mapster;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;

// 表示元素的类
class Element
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public string Name { get; set; }
    public string Type { get; set; }
    public string Comment { get; set; }
    public List<Element> Children { get; set; } = new List<Element>();

    public override string ToString()
    {
        return $"Id: {Id}, ParentId: {ParentId}, Name: {Name}, Type: {Type}, Comment: {Comment}";
    }
}

// 解析器类
class S7CodeParser
{
    private int currentId = 1;

    public List<Element> Parse(string code)
    {
        var elements = new List<Element>();
        var lines = code.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
        var stack = new Stack<Element>();

        foreach (var line in lines.Select(l => l.Trim()))
        {
            // 跳过版本信息行
            if (line.StartsWith("VERSION :"))
            {
                continue;
            }

            // 在开始处理每行时就移除 { S7_SetPoint := 'False' } 标记
            var cleanLine = Regex.Replace(line, @"\{ S7_SetPoint := 'False' \}", "").Trim();

            if (cleanLine.StartsWith("TYPE"))
            {
                // 处理 TYPE 部分，去掉可能的分号
                var typeName = Regex.Match(cleanLine, @"TYPE ""([^""]+)""").Groups[1].Value;
                var newElement = new Element { Id = Interlocked.Increment(ref currentId) - 1, Name = typeName, Type = "TYPE" };
                elements.Add(newElement);
                stack.Push(newElement);
            }
            else if (cleanLine.StartsWith("DATA_BLOCK"))
            {
                var dataBlockName = Regex.Match(cleanLine, @"DATA_BLOCK ""([^""]+)""").Groups[1].Value;
                var newElement = new Element { Id = Interlocked.Increment(ref currentId) - 1, Name = dataBlockName, Type = "DATA_BLOCK" };
                elements.Add(newElement);
                stack.Push(newElement);
            }
            else if (cleanLine.Contains(": Struct"))
            {
                var parts = cleanLine.Split(new[] { ':' }, 2);
                var name = parts[0].Trim();
                var commentMatch = Regex.Match(parts[1], @"//(.*)");
                var comment = commentMatch.Success ? commentMatch.Groups[1].Value.Trim() : "";

                var structElement = new Element { Id = Interlocked.Increment(ref currentId) - 1, Name = name, Type = "STRUCT", Comment = comment };
                if (stack.Count > 0)
                {
                    structElement.ParentId = stack.Peek().Id;
                    stack.Peek().Children.Add(structElement);
                }
                stack.Push(structElement);
            }
            else if (cleanLine.StartsWith("STRUCT"))
            {
                if (stack.Count > 0)
                {
                    var structElement = new Element { Id = Interlocked.Increment(ref currentId) - 1, Name = "AnonymousStruct", Type = "STRUCT" };
                    structElement.ParentId = stack.Peek().Id;
                    stack.Peek().Children.Add(structElement);
                    stack.Push(structElement);
                }
            }
            else if (cleanLine.StartsWith("END_STRUCT"))
            {
                if (stack.Count > 0)
                {
                    stack.Pop();
                }
            }
            else if (cleanLine.Contains(":") && stack.Count > 0)
            {
                var parts = cleanLine.Split(new[] { ':' }, 2);
                var name = parts[0].Trim();
                var typeAndComment = parts[1].Trim();
                var commentMatch = Regex.Match(typeAndComment, @"//(.*)");
                var comment = commentMatch.Success ? commentMatch.Groups[1].Value.Trim() : "";
                var type = commentMatch.Success
                   ? typeAndComment.Substring(0, typeAndComment.IndexOf("//")).Trim().Replace(";", "")
                    : typeAndComment.Replace(";", "").Trim();

                // 去掉类型名称首尾的双引号
                if (type.StartsWith("\"") && type.EndsWith("\""))
                {
                    type = type.Substring(1, type.Length - 2);
                }

                var newElement = new Element { Id = Interlocked.Increment(ref currentId) - 1, Name = name, Type = type, Comment = comment };
                newElement.ParentId = stack.Peek().Id;
                stack.Peek().Children.Add(newElement);
            }
        }

        return elements;
    }

    public void ExpandCustomTypes(List<Element> elements)
    {
        var typeElements = elements.Where(e => e.Type == "TYPE").ToDictionary(e => e.Name, e => e);
        int localCurrentId = currentId;

        void RecursiveExpand(Element parent)
        {
            foreach (var child in parent.Children.ToList())
            {
                if (typeElements.ContainsKey(child.Type))
                {
                    var customType = typeElements[child.Type];
                    foreach (var subChild in customType.Children[0].Children)
                    {
                        var newChild = new Element
                        {
                            // 为子元素重新创建 ID
                            Id = Interlocked.Increment(ref localCurrentId) - 1,
                            ParentId = child.Id,
                            Name = subChild.Name,
                            Type = subChild.Type,
                            Comment = subChild.Comment,
                            Children = subChild.Children.Adapt<List<Element>>()
                        };
                        child.Children.Add(newChild);
                        RecursiveExpand(newChild);
                    }
                }
                RecursiveExpand(child);
            }
        }

        foreach (var element in elements)
        {
            RecursiveExpand(element);
        }
        currentId = localCurrentId;
    }

    public void FixIdsAndParentIds(List<Element> elements)
    {
        int newId = 1;
        var idMapping = new Dictionary<int, int>();

        void RecursiveFix(Element element, int? parentId = null)
        {
            idMapping[element.Id] = newId;
            element.Id = newId++;
            element.ParentId = parentId;

            foreach (var child in element.Children)
            {
                RecursiveFix(child, element.Id);
            }
        }

        foreach (var element in elements)
        {
            RecursiveFix(element, null);
        }
    }
}

class Program
{
    static void Main()
    {
        string code = @"
TYPE ""udt call AGv Send""
VERSION : 0.1
   STRUCT
      ""Call Put"" : Struct
         请求送料类别 : Int;   // 零件号:1=翅片；2=盖板；3=底板；4=大焊环；5=小焊环；6=焊丝；7=焊片；8=中板；9=接头；10=定位柱
         请求送料 : Int;   // 0=无；1=送料
         请求送料离开 : Int;   // 0=无；1=离开
         Spare4 : Int;
         Spare5 : Int;
      END_STRUCT;
      ""Call Pick"" : Struct
         请求取料类别 : Int;   // 零件号:1=翅片；2=盖板；3=底板；4=大焊环；5=小焊环；6=焊丝；7=焊片；8=中板；9=接头；10=定位柱
         请求取料 : Int;   // 0=无；1=取料
         请求取料离开 : Int;   // 0=无；1=离开
         Spare4 : Int;
         Spare5 : Int;
      END_STRUCT;
   END_STRUCT;

END_TYPE

DATA_BLOCK ""MES_F17_OP10_PlcToPC_AGV""
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
   STRUCT 
      产品追溯 : Struct
         Reserved : Array[0..998] of Byte;   // 1=上传成功
      END_STRUCT;
      InterfaceAGV : Struct   // AGV
         L1 { S7_SetPoint := 'False' } : ""udt call AGv Send"";   // 下料输送线L1
         L2 { S7_SetPoint := 'False' } : ""udt call AGv Send"";   // 下料输送线L2
         L3 { S7_SetPoint := 'False' } : ""udt call AGv Send"";   // 下料输送线L3
         L4 { S7_SetPoint := 'False' } : ""udt call AGv Send"";   // 下料输送线L4
         L5 { S7_SetPoint := 'False' } : ""udt call AGv Send"";   // 下料输送线L5
         L7 { S7_SetPoint := 'False' } : ""udt call AGv Send"";   // 下料回流输送线L7
      END_STRUCT;
   END_STRUCT;


BEGIN

END_DATA_BLOCK";

        var parser = new S7CodeParser();
        var elements = parser.Parse(code);
        parser.ExpandCustomTypes(elements);
        parser.FixIdsAndParentIds(elements);

        foreach (var element in elements)
        {
            Console.WriteLine(element);
            PrintChildren(element.Children, 1);
        }
    }

    static void PrintChildren(List<Element> children, int indentLevel)
    {
        var indent = new string(' ', indentLevel * 2);
        foreach (var child in children)
        {
            Console.WriteLine($"{indent}{child}");
            PrintChildren(child.Children, indentLevel + 1);
        }
    }
}